package com.wngbms.fileio.file_transfer;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

@Slf4j
public class BigFileNioSendClient {

    public static Charset charset = StandardCharsets.UTF_8;

    public static void main(String[] args) throws IOException {
//        System.out.println(1024 * 1024 * 128);
//        System.out.println(1 << 27);
        send();
    }

    @SneakyThrows
    private static void send() throws IOException {
        File file = new File("J:\\img0.jpg");
        if (!file.exists()) {
            log.info("文件不存在");
            return;
        }

        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.setOption(StandardSocketOptions.TCP_NODELAY, true);
        socketChannel.connect(new InetSocketAddress("127.0.0.1", 8090));
        socketChannel.configureBlocking(false);

        while (!socketChannel.finishConnect()) {
            Thread.yield();
        }
        log.info("connected");

        ByteBuffer fileNameBuf = charset.encode(file.getName());
        int remaining = fileNameBuf.remaining();

        ByteBuffer buffer = ByteBuffer.allocateDirect(4096);
        buffer.putInt(remaining);

        // read mode
        buffer.flip();
        socketChannel.write(buffer);
        log.info("fileNameLength sent:{}", remaining);

        // 是否需要切换为读模式
        socketChannel.write(fileNameBuf);
        log.info("fileName sent:{}", file.getName());

        buffer.clear();
        buffer.putInt((int) file.length());
        buffer.flip();
        socketChannel.write(buffer);
        log.info("fileLength sent:{}", file.length());

        RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
        FileChannel fileChannel = randomAccessFile.getChannel();

        long transferred = 0, sent = 0;
        while (transferred < file.length()) {
            sent = fileChannel.transferTo(transferred, 1 << 27, socketChannel);
            if (sent == 0) {
                log.info("sent no data");
                Thread.sleep(1000);
            }
            transferred += sent;
            log.info("transferred:{} {}", transferred, file.length());
        }

        log.info("文件发送完成 {} {}", transferred, file.length());

        Thread.sleep(10);
        Thread.sleep(Integer.MAX_VALUE);
        socketChannel.close();
        fileChannel.close();
        randomAccessFile.close();
    }
}
